import gio
import gtk
import threading
from mmxfer import mediatype
from mmxfer import store
import traceback
import tempfile
import time
import os
import gst
from mutagen.easyid3 import EasyID3
import mutagen

class WorkerThread_Convert(threading.Thread):
	create_player_failed=False
	def __init__(self,lstore,bitrate):
		threading.Thread.__init__(self)
		self.lstore=lstore
		self.error_occurred=False
		self.has_player=False
		self.bitrate=bitrate
	def CreatePlayer(self):
		self.player = gst.element_factory_make("playbin", "player")
		self.fakesink = gst.element_factory_make("fakesink", "fakesink")
		self.player.set_property("video-sink", self.fakesink)
		self.bus=self.player.get_bus()
		self.bus.add_signal_watch()
		self.bus.connect("message", self.on_message)
		pluginlist=["audioconvert","audioresample","lame","id3v2mux","filesink"]
		self.plugindict={}
		for name in pluginlist:
			self.plugindict[name]=gst.element_factory_make(name,name)
		self.plugindict["lame"].set_property("bitrate",self.bitrate)
		self.bin = gst.Bin("writer")
		for name in pluginlist:
			self.bin.add(self.plugindict[name])
		pad = self.plugindict["audioconvert"].get_pad("sink")
		ghostpad = gst.GhostPad("sink", pad)
		self.bin.add_pad(ghostpad)
		gst.element_link_many(*[self.plugindict[name] for name in pluginlist])
		self.player.set_property("audio-sink", self.bin)
		self.event=threading.Event()
		self.event.clear()
		self.time_format = gst.Format(gst.FORMAT_TIME)
		self.has_player=True
	def run(self):
		while not self.lstore.quit_event.is_set():
			gtk.gdk.threads_enter()
			task_row=None
			for row in self.lstore:
				if row[store.column("waiting")] \
						and row[store.column("type")]==mediatype.MT_AUDIO_CONVERTIBLE:
					task_row=row
					break
			if task_row is None:
				gtk.gdk.threads_leave()
				self.lstore.quit_event.wait(0.1)
				continue
			task_row[store.column("status")]=mediatype.get_description(mediatype.MT_AUDIO_CONVERTIBLE,False)
			task_row[store.column("waiting")]=False
			uri=task_row[store.column("uri")]
			if not self.has_player and not WorkerThread_Convert.create_player_failed:
				try:
					self.CreatePlayer()
				except:
					#prevent this being tried again and inform the user...
					WorkerThread_Convert.create_player_failed=True
					traceback.print_exc()
					error="Could not create the gstreamer pipeline for conversion.\nConversion requires the `lame' encoder plugin."
					dlg=gtk.MessageDialog(buttons=gtk.BUTTONS_OK,message_format=error,type=gtk.MESSAGE_ERROR)
					dlg.set_title("MMXfer Error")
					dlg.run()
					dlg.destroy()
					gtk.gdk.threads_leave()
					#we continue anyway and allow the conversion to fail `naturally'
			result=False
			dest_name=""
			try:
				src=gio.File(uri).get_path()
				dest_name=tempfile.NamedTemporaryFile(suffix=".mp3",delete=False)
				dest=gio.File(dest_name.name).get_path()
				dest_name.close()
				task_row[store.column("tmp")].append(dest)
				#CONVERT!
				self.error_occurred=False
				self.plugindict["filesink"].set_property("location",dest)
				self.player.set_property("uri", gio.File(uri).get_uri())#ensure actually a uri
				self.event.clear()
				self.player.set_state(gst.STATE_PLAYING)
				gtk.gdk.threads_leave()
				while not self.event.is_set():
					try:
						time.sleep(0.05)
						try:
							gtk.gdk.threads_enter()
							max=self.player.query_duration(self.time_format, None)[0]
							current=self.player.query_position(self.time_format, None)[0]
							row[store.column("progress")]=float(current)/float(max)*100.0
						except:
							pass
						finally:
							gtk.gdk.threads_leave()
						if self.lstore.quit_event.is_set():
							self.player.set_state(gst.STATE_NULL)
							self.event.set()
							self.error_occurred=True
					except:
						traceback.print_exc()
				gtk.gdk.threads_enter()
				self.player.set_state(gst.STATE_NULL)
				self.event.clear()
				#copy our tags across
				if not self.error_occurred:
					old=mutagen.File(src)
					new=EasyID3(dest)
					for key in EasyID3.valid_keys.keys():
						try:new[key]=old[key]
						except:pass
					result=True
			except:
				traceback.print_exc()
			if result:
				type=mediatype.find_type(dest)
				if type == mediatype.MT_AUDIO_UPLOADABLE:
					task_row[store.column("uri")]=dest
					task_row[store.column("type")]=type
					task_row[store.column("status")]=mediatype.get_description(type,True)
					task_row[store.column("progress")]=0.0
				else:
					result=False
			if not result:
				task_row[store.column("type")]=mediatype.MT_UNKNOWN
				task_row[store.column("status")]=mediatype.get_description(mediatype.MT_UNKNOWN,False)
				task_row[store.column("progress")]=0.0
			task_row[store.column("waiting")]=True
			gtk.gdk.threads_leave()
	def progress_callback(self,current,max,row):
		gtk.gdk.threads_enter()
		row[store.column("progress")]=float(current)/float(max)*100.0
		gtk.gdk.threads_leave()
	def on_message(self, bus, message):
		t = message.type
		if t == gst.MESSAGE_EOS:
			self.event.set()
		elif t == gst.MESSAGE_ERROR:
			err, debug = message.parse_error()
			print "Error: %s" % err, debug
			self.error_occurred=True
			self.event.set()
